package threadlocal;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.LongAdder;

/**
 * 卖房场景需求：
 * <pre>
 * 1. 能够统计总销售量
 * 2. 能够统计每个员工(线程)的销售量
 *
 * </pre>
 * @author <a href='https://gitee.com/hzf2281'>codefish</a>
 * @version 1.0.0
 * @since 2022/08/25 上午 10:30
 */
public class HouseSaleDemo {
    private static final House house = new House();

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(10);

        for (int i = 1; i <= 10; i++) {
            new Thread(() -> {
                try{
                    for (int j = 0; j < 5; j++) {
                        house.sale(ThreadLocalRandom.current().nextInt(10));
                    }
                    System.out.println(Thread.currentThread().getName() + "共卖出" + house.getSaleCount() + "套房");
                }finally {
                    latch.countDown();
                    house.removeCount();
                }
            }, "t" + i).start();
        }
        latch.await();
        System.out.println("共卖出" + house.getTotalSaleCount() + "套房");
    }
}

/**
 * 资源类
 */
class House {
    //记录总销售量
    LongAdder totalSale = new LongAdder();
    //记录每个员工(线程)的销售量

    // jdk 8 之前的初始化方式

//   ThreadLocal<Long> perSale = new ThreadLocal<Long>(){
//
//       //initialValue()方法用于初始化变量副本的值,
//       // 只有当线程第一次调用get()或者在remove()后第一次调用get()时才会执行。
//       // 一般通过匿名内部类的方式重新这个方法
//       @Override
//       protected Long initialValue() {
//           return 0L;
//       }
//   };

    // jdk 8版本引入了函数式编程的概念，ThreadLocal添加了新的静态方法withInitial()，接收一个Supplier做为初始化时调用的方法，并且返回对应的ThreadLocal实例
    ThreadLocal<Long> perSale = ThreadLocal.withInitial(
            //接收一个Supplier，调用时返回0
            () -> 0L
    );

    public void sale(int x) {
        for (int i = 0; i < x; i++) {
            totalSale.increment();
            perSale.set(perSale.get() + 1);
        }
//        System.out.println("当前一共卖出" + totalSale.sum() + "套房");
//        System.out.println(threadTag() + "卖出" + perSale.get() + "套房");
    }

    public long getSaleCount() {
        return perSale.get();
    }

    public long getTotalSaleCount() {
        return totalSale.sum();
    }

    /**
     * 完成后移除threadlocal中的变量副本，否则导致内存泄漏
     */
    public void removeCount(){
        perSale.remove();
    }

    private String threadTag() {
        return "[" + Thread.currentThread().getName() + "]";
    }
}



